package org.aplikator.client.local.widgets;

import com.github.gwtbootstrap.client.ui.*;
import com.github.gwtbootstrap.client.ui.constants.IconType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.SuggestOracle;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
import com.google.gwt.user.client.ui.Widget;
import org.aplikator.client.local.Aplikator;
import org.aplikator.client.shared.data.ItemSuggestion;
import org.aplikator.client.shared.data.Record;
import org.aplikator.client.shared.descriptor.PropertyDTO;
import org.aplikator.client.shared.descriptor.SuggestionsDTO;
import org.aplikator.client.shared.descriptor.ViewDTO;
import org.jboss.errai.common.client.api.ErrorCallback;
import org.jboss.errai.common.client.api.RemoteCallback;

//import com.google.gwt.user.client.ui.*;

public class ReferenceFieldWidget extends ContainerFieldBase implements DataField<Integer> {

    public interface RefFormWidgetResources extends ClientBundle {
        public static final RefFormWidgetResources INSTANCE = GWT.create(RefFormWidgetResources.class);

        @Source("RefFormWidget.css")
        public RefFormWidgetCss css();

        @Source("images/icons/find16.png")
        ImageResource find();
    }

    public interface RefFormWidgetCss extends CssResource {
        public String refSearchLeft();

        public String refSearchRight();

        public String refSearchAll();

        public String refHeader();
    }

    static {
        RefFormWidgetResources.INSTANCE.css().ensureInjected();
    }


    private Button buttonSearch;
    private Typeahead typeahead;
    private TextBox searchBox;

    private Integer value;// TODO change to pk
    private PropertyDTO property;
    private ViewDTO view;
    private TableInterface table;
    private Modal dialogBox;
    private FluidContainer dialogContents;
    //private GlassPanel glassPanel = new GlassPanel();
    private Record selectedRecord = null;
    private boolean dirty;

    public ReferenceFieldWidget(String caption, ViewDTO view, Widget child) {
        super();
        this.view = view;

        wrapper = new ControlGroup();
        this.label = new ControlLabel(caption);
        this.controls = new Controls();
        initWidget(wrapper);
        wrapper.add(this.label);
        wrapper.add(this.controls);

        // forms container
        dataPanel = new FluidRow();
        dataPanel.add(child);


        buttonSearch = new Button("", IconType.SEARCH);
        buttonSearch.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                if (dialogBox == null) {
                    dialogBox = createDialogBox();
                }
                dialogContents.setPixelSize(Window.getClientWidth() - 40, Window.getClientHeight() - 210);
                // dialogBox.center();
                // dialogBox.setPopupPosition(Window.getScrollLeft(),
                // Window.getScrollTop());
                dialogBox.setWidth(Window.getClientWidth() - 40);
                dialogBox.setMaxHeigth(""+(Window.getClientHeight()-140)+"px");
                dialogBox.show();

                if (ReferenceFieldWidget.this.view.getActivePrimarySortProperty() != null) {
                    ReferenceFieldWidget.this.view.setSearchString(searchBox.getText());
                    table.search();
                } else {
                    table.reload();
                }
            }
        });

        FluidRow searchPanel = new FluidRow();
        searchPanel.addStyleName(RefFormWidgetResources.INSTANCE.css().refHeader());
        if (view.getActivePrimarySortProperty() != null) {
            ItemSuggestOracle oracle = new ItemSuggestOracle();
            typeahead = new Typeahead(oracle);
            searchBox = new TextBox();
            typeahead.setWidget(searchBox);
            resetSearchBox();
            //searchBox.setStyleName(RefFormWidgetResources.INSTANCE.css().refSearchLeft());
            searchBox.addFocusHandler(new FocusHandler() {
                public void onFocus(FocusEvent event) {
                    searchBox.setText("");
                }
            });
            typeahead.setUpdaterCallback(new Typeahead.UpdaterCallback() {
                public String onSelection(Suggestion selectedSuggestion){
                    int id = ((ItemSuggestion) selectedSuggestion).getId();
                    selectedRecord = ((ItemSuggestion) selectedSuggestion).getRecord();
                    setValue(id, true);
                    return ((ItemSuggestion) selectedSuggestion).getDisplayString();
                }
            });
            InputAddOn searchGroup = new InputAddOn();
            searchGroup.setPrependText("Search:");
            searchGroup.add(typeahead);
            searchGroup.add(buttonSearch);
            searchPanel.add(searchGroup);

        } else{
            searchPanel.add(buttonSearch);
        }
        //searchPanel.setHeight("20px");

        //buttonSearch.setStyleName(RefFormWidgetResources.INSTANCE.css().refSearchRight());
        //searchPanel.setStyleName(RefFormWidgetResources.INSTANCE.css().refSearchAll());
        Well well = new Well();
        controls.add(well);
        well.add(searchPanel);
        well.add(dataPanel);
        //navigationPanel.setStyleName(ContainerFieldResources.INSTANCE.css().contentsHeader());
        //basePanel.setStyleName(ContainerFieldResources.INSTANCE.css().contentsFrame());
        //dataPanel.setStyleName(ContainerFieldResources.INSTANCE.css().contentsHolder());

    }

    private void resetSearchBox() {
        if (view.getActivePrimarySortProperty() != null) {
            searchBox.setText(view.getActivePrimarySortProperty().getLocalizedName() + ":");
        }
    }

    public PropertyDTO getProperty() {
        return property;
    }

    public void setProperty(PropertyDTO property) {
        this.property = property;

    }

    public void setValue(Integer value) {
        setValue(value, false);
        selectedRecord = null;
        resetSearchBox();
    }

    public void setValue(Integer value, boolean fireEvents) {
        Integer oldValue = this.value;
        this.value = value;
        if (fireEvents) {
            if (value != null && !value.equals(oldValue)) {
                setDirty(true);
            }
            ValueChangeEvent.fireIfNotEqual(this, oldValue, value);
        }
    }

    public Integer getValue() {
        return value;
    }

    public void setEnabled(boolean enabled) {
        buttonSearch.setEnabled(enabled);
        if (searchBox!= null){
            searchBox.setEnabled(enabled);
        }
    }

    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Integer> handler) {
        return this.addHandler(handler, ValueChangeEvent.getType());
    }

    private Modal createDialogBox() {
        dialogContents = new FluidContainer();
        dialogContents.getElement().getStyle().setPadding(0, Style.Unit.PX);
        final Modal dialogBox = new Modal();

        dialogBox.setTitle("Select reference - " + view.getLocalizedName());
        dialogBox.add(dialogContents);
        Style modalBodyStyle = dialogContents.getParent().getElement().getStyle();
        modalBodyStyle.setPaddingBottom(0, Style.Unit.PX);
        modalBodyStyle.setPaddingLeft(0, Style.Unit.PX);
        modalBodyStyle.setPaddingRight(0, Style.Unit.PX);
        //dialogBox.setAnimation(true);
        //dialogBox.setBackdrop(BackdropType.STATIC);
        ModalFooter buttonPanel = new ModalFooter();

        Button OKButton = new Button("OK", new ClickHandler() {

            public void onClick(ClickEvent event) {
                dialogBox.hide();
                selectedRecord = table.getSelectedRecord();
                setValue(table.getSelectedPrimaryKey().getId(), true);
            }

        });
        buttonPanel.add(OKButton);

        Button closeButton = new Button("Cancel", new ClickHandler() {

            public void onClick(ClickEvent event) {
                dialogBox.hide();
            }

        });
        buttonPanel.add(closeButton);
        dialogBox.add(buttonPanel);

        table = TableFactory.create(view, null, null);
        table.asWidget().setSize("100%", "100%");
        dialogContents.add(table);

        return dialogBox;
    }

    public Record getSelectedRecord() {
        return selectedRecord;
    }

    public void setDirty(boolean dirty) {
        this.dirty = dirty;
        /*if (dirty) {
            dataPanel.addStyleName(AplikatorResources.INSTANCE.css().dirty());
        } else {
            dataPanel.removeStyleName(AplikatorResources.INSTANCE.css().dirty());
        }*/
    }

    public boolean isDirty() {
        return dirty;
    }

    public class ItemSuggestOracle extends SuggestOracle {

        public boolean isDisplayStringHTML() {
            return true;
        }

        public void requestSuggestions(SuggestOracle.Request req, SuggestOracle.Callback callback) {
            Aplikator.aplikatorService.call(new ItemSuggestCallback(req, callback)).getSuggestions(view.getId(), req.getQuery());
        }

        class ItemSuggestCallback implements RemoteCallback<SuggestionsDTO>, ErrorCallback {

            private SuggestOracle.Request req;
            private SuggestOracle.Callback callback;

            public ItemSuggestCallback(SuggestOracle.Request r, SuggestOracle.Callback c) {
                req = r;
                callback = c;
            }


            @Override
            public boolean error(Object message, java.lang.Throwable throwable){
                callback.onSuggestionsReady(req, new SuggestOracle.Response());
                return false;
            }

            @Override
            public void callback(SuggestionsDTO dto) {
                callback.onSuggestionsReady(req, new SuggestOracle.Response(dto.getSuggestions()));
            }
        }
    }

}
